package com.gitee.wsl.compose.state

import androidx.compose.runtime.Composable
import androidx.compose.runtime.Stable
import androidx.compose.runtime.State
import androidx.compose.runtime.remember
import arrow.core.Either
import com.gitee.wsl.compose.use.ResetFn
import com.gitee.wsl.compose.use.SetValueFn
import com.gitee.wsl.compose.use.SetterEither
import com.gitee.wsl.compose.use.invoke
import com.gitee.wsl.compose.use.useGetState
import com.gitee.wsl.reflect.Options

/*
  Description: A hook that manage counter.
  Author: Junerver
  Date: 2024/7/8-13:17
  Email: junerver@gmail.com
  Version: v1.0
*/
@ConsistentCopyVisibility
@Stable
data class CounterOptions internal constructor(
    var min: Int = 0,
    var max: Int = 10,
) {
    companion object : Options<CounterOptions>(::CounterOptions)
}

@Composable
internal fun S.useCounter(initialValue: Int = 0, options: CounterOptions): CounterHolder {
    val (current, setCurrent, getCurrent) = useGetState(getTargetValue(initialValue, options))
    val setValue: SetValueFn<Either<Int, (Int) -> Int>> = { value: Either<Int, (Int) -> Int> ->
        val target = value.fold(
            ifLeft = { it },
            ifRight = { it(getCurrent()) }
        )
        setCurrent(getTargetValue(target, options))
    }

    fun inc(delta: Int) {
        setValue { c: Int -> c + delta }
    }

    fun dec(delta: Int) {
        setValue { c: Int -> c - delta }
    }

    fun set(value: Either<Int, (Int) -> Int>) {
        setValue(value)
    }

    fun reset() {
        setValue(initialValue)
    }

    return remember {
        CounterHolder(
            current,
            ::inc,
            ::dec,
            ::set,
            ::reset
        )
    }
}


@Composable
fun S.useCounter(initialValue: Int = 0, optionsOf: CounterOptions.() -> Unit) =
    useCounter(initialValue, remember { CounterOptions.optionOf(optionsOf) })

private fun getTargetValue(value: Int, options: CounterOptions): Int {
    val (min, max) = options
    return value.coerceIn(min, max)
}

@Stable
data class CounterHolder(
    val state: State<Int>,
    val inc: IncFn,
    val dec: DecFn,
    val setValue: SetValueFn<SetterEither<Int>>,
    val reset: ResetFn,
)

// useCounter
internal typealias IncFn = (Int) -> Unit
internal typealias DecFn = (Int) -> Unit